
#ifndef __SESSION_HPP__
#define __SESSION_HPP__

#include "utils.hpp"

// session板块
// 实现会话功能: 包含两个类: session数据类 , session管理类

// 1. session板块
// 成员变量: session ID , 对应的用户ID  , 用户当前的状态 : HAVE_LOGIN , NOT_LOGIN , session的相关定时器, 来实现session定时失效的功能
// 成员函数: 创建会话, 设置状态, 获取状态 , 获取用户ID , 设置定时任务, 获取定时任务

#define SESSION_NORMAL 300000

typedef enum
{
    HAVE_LOGIN,
    NOT_LOGIN
} ss_status;

class Session
{
public:
    Session(uint64_t uid, uint64_t ssid)
        : _ssid(ssid), _uid(uid)
    {
    }

    void set_status(ss_status status) { _status = status; }

    ss_status get_status() { return _status; }

    uint64_t get_user_id() { return _uid; }
    uint64_t get_session_id() { return _ssid; }

    websocket_server::timer_ptr get_timer_ptr() { return _tp; }

    void set_timer_ptr(websocket_server::timer_ptr tp) { _tp = tp; }

private:
    uint64_t _ssid;
    uint64_t _uid;
    ss_status _status;
    websocket_server::timer_ptr _tp;
};

// 2. session管理模块
// 内部成员 : session自增的ID( + 互斥锁) , 建立会话ID和Sessoin类的映射关系 , websocket_server对象用来添加对应的定时任务
// 内置接口 : 创建会话 , 移除会话 , 通过会话ID获取session , 设置会话的定时任务

#define SESSION_FOREVER -1

class Session_manger
{
public:
    Session_manger(websocket_server *web_svr)
        : _web_svr(web_svr), _session_num(0)
    {
    }

    std::shared_ptr<Session> create_session(uint64_t uid)
    {
        // 1. 创建一个新的会话
        // 2. 设置会话内容
        // 3. 将会话加入管理
        uint64_t ss_id;
        {
            std::unique_lock<std::mutex> lock(_mtx);
            ss_id = _session_num++;
        }
        std::shared_ptr<Session> ss_ptr(new Session(uid, ss_id));
        ss_ptr->set_status(HAVE_LOGIN);
        _sessions.emplace(ss_id, ss_ptr);
        return ss_ptr;
    }

    void remove_session(uint64_t ssid)
    {
        std::unique_lock<std::mutex> lock(_mtx);
        // 直接从_sessions中进行移除即可
        _sessions.erase(ssid);
    }

    void append(uint64_t ssid, std::shared_ptr<Session> ss_ptr)
    {
        std::unique_lock<std::mutex> lock(_mtx);
        _sessions.emplace(ssid, ss_ptr);
    }

    std::shared_ptr<Session> get_session_by_ssid(uint64_t ssid)
    {
        std::unique_lock<std::mutex> lock(_mtx);
        if(!_sessions.count(ssid))
            return std::shared_ptr<Session>();
        return _sessions[ssid];
    }

    void set_session_expire_time(uint64_t ssid, int ms)
    {
        // 分为三种情况: 1. 永久存在->定时销毁 2. 定时销毁 -> 永久存在 3. 定时销毁 -> 定时销毁

        std::shared_ptr<Session> ss_ptr = _sessions[ssid];
        if(ss_ptr.get() == nullptr)
        {
            return ;
        }
        websocket_server::timer_ptr tp = ss_ptr->get_timer_ptr();
        if (tp.get() == nullptr && ms == SESSION_FOREVER)
        {
            return;
        }
        else if (tp.get() == nullptr && ms != SESSION_FOREVER)
        {
            // 从永久存在 -> 定时销毁
            tp = _web_svr->set_timer(ms, std::bind(&Session_manger::remove_session, this, ssid));
            ss_ptr->set_timer_ptr(tp);
        }
        else if (tp.get() != nullptr && ms == SESSION_FOREVER)
        {
            // 从定时销毁 -> 永久存在

            // 1. 让销毁函数先直接进行执行
            // 2. 重新添加一个定时销毁函数
            tp->cancel();
            ss_ptr->set_timer_ptr(websocket_server::timer_ptr());

            _web_svr->set_timer(0, std::bind(&Session_manger::append, this, ssid, ss_ptr));
        }
        else if (tp.get() != nullptr && ms != SESSION_FOREVER)
        {
            // 定时销毁 -> 定时销毁
            // 1. 先让销毁函数进行执行
            // 2. 重新添加一个销毁函数
            tp->cancel();
            ss_ptr->set_timer_ptr(websocket_server::timer_ptr());
            _web_svr->set_timer(0, std::bind(&Session_manger::append, this, ssid, ss_ptr));

            tp = _web_svr->set_timer(ms, std::bind(&Session_manger::remove_session, this, ssid));
            ss_ptr->set_timer_ptr(tp);
        }
    }

private:
    uint64_t _session_num;
    std::mutex _mtx;
    std::unordered_map<uint64_t, std::shared_ptr<Session>> _sessions;
    websocket_server *_web_svr;
};

#endif